package cn.ycq.im.chat.clients;

import cn.ycq.im.chat.CmdTransport;
import cn.ycq.im.chat.MessageBuildUtils;
import cn.ycq.im.commons.utils.JsonUtils;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
@Slf4j
public abstract class ClientManager {
    private static Map<String, ChannelListWraper> clientMaps = new ConcurrentHashMap<>();

    private ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static void addClient(Channel channel, String userName){
        ChannelListWraper channelListWraper = clientMaps.computeIfAbsent(userName, un -> new ChannelListWraper());
        channelListWraper.addChannel(channel);
        log.info("添加客户端：{}- ({})，当前客户端数量:{}",userName,channel.id().asShortText(),channelListWraper.channelNum());

        pushOnlineMessage();
        pushOnlineListMessage(userName);
    }

    private static void pushOnlineListMessage(String currentUserName) {
        List<String> userList = new ArrayList<>();
        for (String name : clientMaps.keySet()) {
                userList.add(name);
        }

        CmdTransport onlineMessage = MessageBuildUtils.getPushOnlineUserListMessage(userList);
        writeAndFlusFuncEach((name,cl)->{
             cl.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(onlineMessage)));
        });
    }

    private static void pushOnlineMessage() {
        CmdTransport onlineMessage = MessageBuildUtils.getPushOnlineMessage((long) clientMaps.size());
        writeAndFlusFuncEach((name,cl)->{
            cl.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(onlineMessage)));
        });
    }

    public static void removeClient(Channel channel,String userName){
         if(userName == null){
            return ;
        }
        ChannelListWraper channelListWraper = clientMaps.get(userName);
        if(ObjectUtils.isEmpty(channelListWraper)){
            return;
        }
        if(channelListWraper.hasChannel(channel.id())){
            channelListWraper.removeChannel(channel.id());
            log.info("删除客户端：{}- ({})，当前客户端数量:{}",userName,channel.id().asShortText(),channelListWraper.channelNum());
        }
        if(channelListWraper.channelNum() == 0){
            clientMaps.remove(userName);
            log.info("删除channelListWraper包装类：{}- ({})",userName,channel.id().asShortText());

            pushOnlineMessage();
            pushOnlineListMessage(userName);
        }
    }

    public static void writeAndFlush(String name, String msg) {
        String meMessage = JsonUtils.objectToJson(MessageBuildUtils.getChatMessage(1, name, msg));
        String youMessage =  JsonUtils.objectToJson(MessageBuildUtils.getChatMessage(2, name, msg));

        for (Map.Entry<String, ChannelListWraper> wraperEntry : clientMaps.entrySet()) {
            ChannelListWraper listWraper = wraperEntry.getValue();
            if(wraperEntry.getKey().equals(name)){
                listWraper.writeAndFlush(new TextWebSocketFrame(meMessage));
            }else{
                listWraper.writeAndFlush(new TextWebSocketFrame(youMessage));
            }
        }
    }

    public static void writeAndFlusFuncEach(BiConsumer<String,ChannelListWraper> consumer) {
        for (Map.Entry<String, ChannelListWraper> wraperEntry : clientMaps.entrySet()) {
            String name = wraperEntry.getKey();
            ChannelListWraper listWraper = wraperEntry.getValue();
            consumer.accept(name,listWraper);
        }
    }

    public static boolean hasClient(String name) {
        return clientMaps.containsKey(name);
    }

    public static ChannelListWraper getClientListWrapper(String name) {
        return clientMaps.get(name);
    }
}
